package queue

import (
	"APT/internal/consts"
	"APT/internal/dao"
	"APT/internal/library/airhousePublicApi"
	"APT/internal/library/cache"
	"APT/internal/library/contexts"
	_ "APT/internal/logic"
	"APT/internal/model"
	"APT/internal/model/entity"
	"APT/internal/model/input/input_app_member"
	"APT/internal/model/input/input_refund"
	"APT/internal/service"
	"APT/utility/rabbitmq"
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
	_ "github.com/gogf/gf/contrib/nosql/redis/v2"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/guid"
	amqp "github.com/rabbitmq/amqp091-go"
)

var (
	PlaceOrderLogger = g.Log().Path("logs/MQ/" + consts.RabbitMQQueueNamePlaceOrder)
)

func PlaceOrder() {
	var (
		ctx          = gctx.New()
		MQMsg        <-chan amqp.Delivery
		exchangeName = consts.RabbitMQExchangeName
		QueueName    = consts.RabbitMQQueueNamePlaceOrder
		MQConnStruct *rabbitmq.MQConnection
		err          error
	)
	g.DB().SetLogger(PlaceOrderLogger)
	// 设置缓存适配器
	cache.SetAdapter(ctx)
	MQConnStruct = &rabbitmq.MQConnection{
		Conn:         rabbitmq.Conn,
		Chan:         nil,
		ExchangeName: exchangeName,
		QueueName:    QueueName,
		RouteKey:     fmt.Sprintf("%s.%s", exchangeName, QueueName),
	}
	if err = MQConnStruct.Channel(); err != nil {
		err = gerror.New("创建队列失败")
		goto ERR
	}
	if err = MQConnStruct.Exchange("topic", true, false); err != nil {
		err = gerror.New("创建交换机失败")
		goto ERR
	}
	if err = MQConnStruct.Queue(true, false, nil); err != nil {
		err = gerror.New("创建通道失败")
		goto ERR
	}
	if err = MQConnStruct.Bind(); err != nil {
		err = gerror.New("交换机绑定队列失败")
		goto ERR
	}
	PlaceOrderLogger.Info(ctx, QueueName+" Queue START SUCCESSFUL")
	if MQMsg, err = MQConnStruct.Consume(guid.S(), false); err != nil {
		PlaceOrderLogger.Error(ctx, err.Error())
		return
	}
	for msg := range MQMsg {
		ctx = gctx.New()
		orderSn := gvar.New(msg.Body).String()
		PlaceOrderLogger.Info(ctx, "--[start]----------------------------------------------")
		PlaceOrderLogger.Info(ctx, orderSn)
		if g.IsEmpty(orderSn) {
			PlaceOrderLogger.Error(ctx, "订单号错误")
			_ = msg.Ack(false)
			continue
		}

		if orderSn[:1] == "C" {
			// TODO -出行订单支付完成
			if err = service.PayService().HandleCarOrderMq(ctx, string(msg.Body), PlaceOrderLogger); err != nil {
				PlaceOrderLogger.Error(ctx, err.Error())
			}
		} else if orderSn[:1] == "S" {
			// TODO -按摩订单支付完成
			if err = service.PayService().HandleSpaOrderMq(ctx, string(msg.Body), PlaceOrderLogger); err != nil {
				PlaceOrderLogger.Error(ctx, err.Error())
			}
		} else if orderSn[:1] == "F" {
			// TODO 餐饮订单支付完成
			if err = service.PayService().HandleFoodOrderMq(ctx, string(msg.Body), PlaceOrderLogger); err != nil {
				PlaceOrderLogger.Error(ctx, err.Error())
			}
		} else if orderSn[:1] == "H" {
			if orderSn[:2] == "HC" {
				// TODO 酒店变更完成
				if err = HandleChangeMQ(ctx, msg); err != nil {
					PlaceOrderLogger.Error(ctx, err.Error())
				}
			} else {
				// TODO 酒店订单支付完成
				if err = HandleStayMQ(ctx, msg); err != nil {
					PlaceOrderLogger.Error(ctx, err.Error())
					if err = cache.Instance().Set(ctx, fmt.Sprintf("PayOrderSn_%s", string(msg.Body)), "SUCCESS", gtime.M*10); err != nil {
						PlaceOrderLogger.Error(ctx, err)
					}
				}
			}
		}
		if err == nil && !g.IsEmpty(orderSn) {
			if err = cache.Instance().Set(ctx, fmt.Sprintf("PayOrderSn_%s", string(msg.Body)), "SUCCESS", gtime.M*10); err != nil {
				PlaceOrderLogger.Error(ctx, err)
			}
		}
		_ = msg.Ack(false)
	}
ERR:
	PlaceOrderLogger.Error(ctx, err)
	panic(err)
}

func HandleStayMQ(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		PmsBalTransaction entity.PmsTransaction
		// PmsAppStay PmsCouponTransaction entity.PmsTransaction
		PmsAppStay          *entity.PmsAppStay
		MemberInfo          *entity.PmsMember
		cookieBookerParams  *airhousePublicApi.CreateStayJSONDataRequest
		BookerResponse      *airhousePublicApi.CreateStayJSONDataResponse
		BookerResponseBytes []byte
		tx                  gdb.TX
		OrderSn             string
	)
	OrderSn = gvar.New(msg.Body).String()
	if tx, err = g.DB().Begin(ctx); err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
			if BookerResponseBytes, err = json.Marshal(&BookerResponse.Data); err != nil {
				return
			}
			if err = rabbitmq.SendMqMessage(ctx, &rabbitmq.SendMqMessageParams{
				ExchangeName: consts.RabbitMQExchangeName,
				QueueName:    consts.RabbitMQQueueNameOrderStay,
				DataByte:     BookerResponseBytes,
				Header:       nil,
			}); err != nil {
				return
			}
		}
	}()
	// 查询住宿单信息
	if err = dao.PmsAppStay.Ctx(ctx).TX(tx).Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).Scan(&PmsAppStay); err != nil {
		err = gerror.New("查询住宿单信息失败")
		return
	}
	if PmsAppStay.OrderStatus != "WAIT_PAY" {
		err = gerror.New("订单状态错误")
		return
	}
	// 查询用户信息
	if err = dao.PmsMember.Ctx(ctx).TX(tx).Where(dao.PmsMember.Columns().Id, PmsAppStay.MemberId).Scan(&MemberInfo); err != nil {
		err = gerror.New("查询用户信息失败")
		return
	}
	// 查询是否存在未支付的余额支付
	PlaceOrderLogger.Info(ctx, "查询是否存在未支付的余额支付")
	if err = dao.PmsTransaction.Ctx(ctx).TX(tx).
		Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
		Where(dao.PmsTransaction.Columns().PayStatus, "WAIT").
		Where(dao.PmsTransaction.Columns().PayType, "BAL").
		Scan(&PmsBalTransaction); err != nil && !errors.Is(err, sql.ErrNoRows) {
		return
	}
	contexts.SetMemberUser(ctx, &model.MemberIdentity{
		PmsMember: MemberInfo,
		App:       "",
		LoginAt:   nil,
	})
	// 是否存在未支付的余额支付信息
	if !g.IsEmpty(PmsBalTransaction) {
		// 扣除余额
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      MemberInfo.Id,
			Scene:         "HOTEL",
			Type:          "CONSUME",
			ChangeBalance: PmsBalTransaction.Amount * -1,
			OrderSn:       PmsBalTransaction.OrderSn,
			Des:           "支付订房费用",
		}, tx); err != nil {
			// 退三方支付金额
			return
		}

		// 修改支付订单状态
		if _, err = dao.PmsTransaction.Ctx(ctx).TX(tx).OmitEmptyData().
			Where(dao.PmsTransaction.Columns().TransactionSn, PmsBalTransaction.TransactionSn).
			Where(dao.PmsTransaction.Columns().PayStatus, "WAIT").
			Update(entity.PmsTransaction{
				PayAmount: PmsBalTransaction.Amount,
				PayStatus: "DONE",
				PayTime:   gtime.Now(),
			}); err != nil {
			return
		}
	}

	// 获取AIRHOST下单参数
	if cookieBookerParams, err = service.HotelService().CreateStayParams(ctx, OrderSn); err != nil {
		return
	}
	// 提交订单
	if BookerResponse, err = service.HotelService().CreateStay(ctx, cookieBookerParams, tx); err != nil {
		return
	}
	// 修改住宿订单为支付完成
	if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).Update(g.Map{
		dao.PmsAppStay.Columns().OrderStatus: "HAVE_PAID",
		dao.PmsAppStay.Columns().Uuid:        BookerResponse.Data.ID,
		dao.PmsAppStay.Columns().Booker:      BookerResponse.Data.Booker.ID,
	}); err != nil {
		return
	}

	// 修改入住人ID
	if _, err = dao.PmsGuestProfile.Ctx(ctx).TX(tx).Where(g.Map{
		dao.PmsGuestProfile.Columns().Uid: PmsAppStay.Booker,
	}).Data(g.Map{
		dao.PmsGuestProfile.Columns().Uid: BookerResponse.Data.Booker.ID,
	}).Update(); err != nil {
		return
	}

	// 修改房间订单为支付完成
	if _, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).Where(dao.PmsAppReservation.Columns().OrderSn, OrderSn).Update(g.Map{
		dao.PmsAppReservation.Columns().OrderStatus: "HAVE_PAID",
		dao.PmsAppReservation.Columns().MainGuest:   BookerResponse.Data.Booker.ID,
	}); err != nil {
		return
	}

	if err = cache.Instance().Set(ctx, "PayOrderSn_"+OrderSn, "HAVE_PAID", gtime.M*10); err != nil {
		return
	}

	// 酒店订单支付成功
	if _, err = dao.PmsAppStayLog.Ctx(ctx).OmitEmptyData().Insert(&entity.PmsAppStayLog{
		OrderId:     PmsAppStay.Id,
		ActionWay:   "HAVE_PAID",
		Remark:      "订单支付",
		OperateType: "USER",
		OperateId:   PmsAppStay.MemberId,
	}); err != nil {
		return
	}

	return
}
func HandleChangeMQ(ctx context.Context, msg amqp.Delivery) (err error) {
	var (
		PmsAppReservationChange *entity.PmsAppReservationChange
		PmsAppReservation       *entity.PmsAppReservation
		BookerResponse          *airhousePublicApi.RetrieveRoomReservationJSONDataResponse
		tx                      gdb.TX
		OrderSn                 string
		ChangeType              string
	)
	OrderSn = gvar.New(msg.Body).String()
	if tx, err = g.DB().Begin(ctx); err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()
	// 查询住宿变更单信息
	if err = dao.PmsAppReservationChange.Ctx(ctx).TX(tx).Where(dao.PmsAppReservationChange.Columns().ChangeOrderSn, OrderSn).Scan(&PmsAppReservationChange); err != nil {
		err = gerror.New("查询住宿单信息失败")
		return
	}
	if PmsAppReservationChange.ChangeStatus != "ING" {
		err = gerror.New("住宿变更单状态错误")
		return
	}
	// 查询住宿单信息
	if err = dao.PmsAppReservation.Ctx(ctx).TX(tx).Where(dao.PmsAppReservation.Columns().Id, PmsAppReservationChange.OrderId).Scan(&PmsAppReservation); err != nil {
		return
	}
	if g.IsEmpty(PmsAppReservation) {
		err = gerror.New("住宿单不存在")
		return
	}

	// 变更人数
	if PmsAppReservationChange.ChangeType == "PEOPLE" {
		if PmsAppReservation.IsChangePeople == "Y" {
			err = gerror.New("该订单已变更过人数")
			return
		}
		ChangeType = "CHANGE_PEOPLE_NUM"
		// 人数变更
		if _, err = airhousePublicApi.UpdateRoomReservationPost(ctx, PmsAppReservation.Uuid, g.Map{
			"adult_count":  PmsAppReservationChange.NewAdultCount,
			"child_count":  PmsAppReservationChange.NewChildCount,
			"infant_count": PmsAppReservationChange.NewInfantCount,
			"booking_fee":  PmsAppReservationChange.ChangeAmount + PmsAppReservation.BookingFee,
		}); err != nil {
			// 未获取到房间信息需要退款
			if err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
				OrderSn:      OrderSn,
				RefundAmount: 0,
			}, tx); err != nil {
				return
			}
			return
		}
		// 回写住宿单变更信息
		if _, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).Where(dao.PmsAppReservation.Columns().Id, PmsAppReservationChange.OrderId).Update(g.Map{
			dao.PmsAppReservation.Columns().IsChangePeople:   "Y",
			dao.PmsAppReservation.Columns().IsChangePeopleId: PmsAppReservationChange.Id,
			dao.PmsAppReservation.Columns().AdultCount:       PmsAppReservationChange.NewAdultCount,
			dao.PmsAppReservation.Columns().ChildCount:       PmsAppReservationChange.NewChildCount,
			dao.PmsAppReservation.Columns().InfantCount:      PmsAppReservationChange.NewInfantCount,
		}); err != nil {
			return
		}
	}
	// 变更日期
	if PmsAppReservationChange.ChangeType == "DATE" {
		if PmsAppReservation.IsChangeDate == "Y" {
			err = gerror.New("该订单已变更过人数")
			return
		}
		ChangeType = "CHANGE_DATE"
		// 日期变更
		if BookerResponse, err = airhousePublicApi.UpdateRoomReservationPost(ctx, PmsAppReservation.Uuid, g.Map{
			"checkin_date":  PmsAppReservationChange.NewCheckinDate.Format("Y-m-d"),
			"checkout_date": PmsAppReservationChange.NewCheckoutDate.Format("Y-m-d"),
			"booking_fee":   PmsAppReservationChange.ChangeAmount + PmsAppReservation.BookingFee,
		}); err != nil {
			// 续住失败
			if err = cache.Instance().Set(ctx, "PayOrderSn_"+OrderSn, "HC_DATE_FAIL", gtime.S*60); err != nil {
				return
			}
			// 未获取到房间信息需要退款
			if err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
				OrderSn:      OrderSn,
				RefundAmount: 0,
			}, tx); err != nil {
				return
			}
			return
		}
		if g.IsEmpty(BookerResponse.Data.RoomUnit.ID) {
			// 续住失败
			if err = cache.Instance().Set(ctx, "PayOrderSn_"+OrderSn, "HC_DATE_FAIL", gtime.S*60); err != nil {
				return
			}
			// 未获取到房间信息需要退款
			if err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
				OrderSn:      OrderSn,
				RefundAmount: 0,
			}, tx); err != nil {
				return
			}
		}
		// 回写住宿单变更信息
		if _, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).Where(dao.PmsAppReservation.Columns().Id, PmsAppReservationChange.OrderId).Update(g.Map{
			dao.PmsAppReservation.Columns().IsChangeDate:   "Y",
			dao.PmsAppReservation.Columns().IsChangeDateId: PmsAppReservationChange.Id,
			dao.PmsAppReservation.Columns().CheckinDate:    PmsAppReservationChange.NewCheckinDate,
			dao.PmsAppReservation.Columns().CheckoutDate:   PmsAppReservationChange.NewCheckoutDate,
			dao.PmsAppReservation.Columns().BookingFee:     gdb.Raw(fmt.Sprintf("booking_fee+%f", PmsAppReservationChange.ChangeAmount)),
		}); err != nil {
			return
		}
	}
	// 修改住宿订单为支付完成
	if _, err = dao.PmsAppReservationChange.Ctx(ctx).TX(tx).Where(dao.PmsAppReservationChange.Columns().ChangeOrderSn, OrderSn).Update(g.Map{
		dao.PmsAppReservationChange.Columns().ChangeStatus: "DONE",
		dao.PmsAppReservationChange.Columns().DoneDate:     gtime.Now(),
	}); err != nil {
		return
	}
	// 更新主订单的总订单金额
	if err = service.PayService().PayAmountChange(ctx, tx, PmsAppReservationChange.OrderSn); err != nil {
		return
	}

	var (
		PmsAppStay entity.PmsAppStay
	)
	if err = dao.PmsAppStay.Ctx(ctx).Where(g.MapStrAny{
		dao.PmsAppStay.Columns().OrderSn: PmsAppReservationChange.OrderSn,
	}).Scan(&PmsAppStay); err != nil && errors.Is(err, sql.ErrNoRows) {
		return
	}
	if g.IsEmpty(PmsAppStay) {
		err = gerror.New("该订单无需处理")
		return
	}
	if _, err = dao.PmsAppStayLog.Ctx(ctx).OmitEmptyData().Insert(&entity.PmsAppStayLog{
		OrderId:     PmsAppStay.Id,
		ActionWay:   ChangeType,
		Remark:      gvar.New(PmsAppReservationChange.Id).String(),
		OperateType: "USER",
		OperateId:   PmsAppStay.MemberId,
	}); err != nil {
		return
	}

	return
}
